\chapter{Narcissus}
\label{Narcissus}
Voor het prototype zal er gebruik gemaakt worden van Narcissus, een open source JavaScript 
engine die geschreven is in JavaScript, en juist dit laatste maakt het interessant. Het feit dat Narcissus volledig uit JavaScript
bestaat, maakt het mogelijk om een veiligheidsarchitectuur te ontwikkelen waarvoor geen client side aanpassingen nodig zijn. 
Code van third party componenten zouden kunnen uitgevoerd worden in een aagepaste versievan Narcissus, 
waarin er bepaalde policy's kunnen afgedwongen worden om functies af the schermen. 

Narcissus werd eerst ontwikeld door Brendan Eich, de uitvindider an JavaScript, als proof-of-concept.
Daarna werd Narcissus verder ontwikkeld om het te gebruikenals engine waarin nieuwe taalfeatures voor JavaScript zouden kunnen getest worden. 
Narcissus is hier goed voor geschikt omdat het een veel kleinere codebase heeft dan een doorsnee JavaScript engine. 
Daarbij komt nog dat het geschreven is in JavaScript,een dynamische scripttaal waarin snel ontikkeld kan worden.
Momenteel werkt Narcissus enkel als het draait binnen SpiderMonkey, de JavaScript engine van Firefox.

Dit hoofdstuk beschrijft de werking van Narcissus, het testproces en de testresultaten.


\pagebreak

\section{Werking}
Alhoewel het concept van een JavaScript engine die geschreven is in JavaScript vrij verwarrend 
kan zijn, is de manier hoe Narcissus in elkaar zit helemaal niet zo bijzonder. Het is makkelijker in te 
beelden dat het een andere programmeertaal evalueert, het blijft qua concept hetzelfde.

Narcissus werkt zelf als een doorsnee interpreter, zo wordt er gebruik gemaakt van een lexer en 
een parser om de programma tekst om te zetten in een interne gegevensstructuur die een abstract 
syntax tree (ast) of parse tree genoemd wordt. Deze gegevensstructuur wordt dan diepte eerst 
uitgevoerd en zo wordt de code ge\"evalueerd. Veel van de standaard operaties zijn in Narcissus niet helemaal opnieuw ge\"implementeerd en worden deze van de JavaScript engine van de browser herbruikt. Dit zijn de heel elementaire operaties zoals de wiskundige bewerkingen
(+, -, *, /, etc), booleaanse operaties (\&\&, ==, !=, etc) en andere functies (document.alert(), document.cookie, etc). 

\begin{figure}
		\centering
 		\includegraphics[width=0.80\textwidth]{img/werking_narcissus.png}
 		\caption{Diagram: werking van Narcissus}
		\label{figWerkingnarc}
\label{Diagram: werking van Narcissus}
\end{figure}

Figuur \ref{figWerkingnarc} toont een schematische voorstelling van hoe een stuk code ge\"evalueerd wordt. 
\begin{itemize}
  \setlength{\parskip}{0.0in}
  \setlength{\itemindent}{1.0em}
	\item In stap 1 zal SpiderMonkey alle bestanden van Narcissus uitvoeren. (jsparse, jsexec,..)
	\item In stap 2 zal Narcissus een sukje code beginnen evalueren. De codestring wordt geparset en omgezet naar tokens.
	\item In stap 3 zal de code een oproep doen naar een built-in JavaScript functie. Narcissus bepaald aan de hand van de token welke functie er uitgevoerd moet worden voor die bepaalde token(s).
	\item In stap 4 zal Narcissus deze oproep doorgeven aan SpiderMonkey.
\end{itemize}

\pagebreak

\subsection{Narcissus context}
Code die ge\"evalueerd wordt in Narcissus, draait binnen een andere context dan de code van 
Narcissus zelf. De code van Narcissus wordt in de context van SpiderMonkey uitgevoerd.
Code die uitgevoerd wordt in de context van Narcissus heeft geen invloed op de code die uitgevoerd wordt in de context van SpiderMonkey.

\medskip
\begin{lstlisting}[caption=Voorbeeld afscherming van SpiderMonkey context.]
  var a = 1;
  Narcissus.interpreter.evauate("alert(a);"); //var a undefined in Narcissus context
\end{lstlisting}

Dit wilt echter niet zeggen dat als variabelen gedeclareerd worden binnen Narcissus, 
ze ook rechtstreeks beschikbaar zijn in de global scope van SpiderMonkey. Hiermee wordt enkel bedoeld 
dat ze vanuit SpiderMonkey enkel toegankelijk zijn via Narcissus.

\medskip
\begin{lstlisting}[caption=Voorbeeld afschemring van Narcissus context.]
  Narcissus.interpreter.evaluate("var a = 1");
  alert(a); //var a undefined in SpiderMonkey context
  Narcissus.interpreter.evaluate("alert(a);"); //var a beschikbaar via Narcissus
\end{lstlisting}

Narcissus werkt als een sandbox waar niet uitgebroken kan worden, een veronderstelling die in Hoofdstuk 3 verder besproken wordt. 
Het heeft een eigen omgeving waar de variabelen opgeslagen worden. De variabelen gedeclareerd in de Spidermonkey context 
zijn daarin niet beschikbaar. Dit is belangrijk omdat het niet wenselijk zou zijn dat de structuur van Narcissus van 
binnen uit aangepast zou kunnen worden. Voor bepaalde functies kan het zijn dat Narcissus letterlijk de 
versie gebruikt van Spidermonkey. In die zin wordt er wel functionaliteit gebruikt uit Spidermonkey. 
Dit kan potenti\"ele gevaren opleveren, en kan best in het achterhoofd gehouden worden. 
Uiteraard wanneer er onbetrouwbare code uitgevoerd wordt, zal dit binnen de context van Narcissus moeten gebeuren. 


\subsection{Code uitvoering in Narcissus}

Het inladen van Narcissus is zeer eenvoudig. De bestanden waaruit Narcissus bestaat, 
kunnen via de script-tag aan de pagina worden toegevoegd.

\medskip
\begin{lstlisting}[caption=Inladen van Narcissus.]
  <script type="text/javascript;version=1.7" src="lib/jsdefs.js"> </script>
  <script type="test/javascript;version=1.7" src="lib/jslex.js" > </script>
  ...
  <script type="text/javascript;version=1.7" src="lib/jsexec.js" > </script>
\end{lstlisting}

Scripts uitvoeren in Narcissus is het best te vergelijken met de eval functie van javascript. Deze 
neemt een string aan als argument, die ge\"interpreteerd wordt als code en meteen uitgevoerd wordt.

\medskip
\begin{lstlisting}[caption=Inladen van Narcissus.]
  <script type="text/javascript;version=1.7">
    Nacissus.interpreter.evaluate('alert("Hello, world!");');
  </script>
\end{lstlisting}

Narcissus heeft zelf nog geen methode om de code vanuit bestanden in te lezen, hiervoor is een 
methode geschreven die dit wel mogelijk maakt. Dit is niet enkel belangrijk voor de tests, ook in 
het prototype zal er uit bestanden moeten kunnen worden ge\"evalueerd. Deze methode maakt gebruik van het XMLHttpRequest object.
Dit brengt wel een limitatie met zich mee. Aangezien de XMLHttpRequest enkel request binnen zijn origin (Zie Sectie 1.3) kan sturen, kunnen er enkel locale JavaScript bestanden ge\"evalueerd worden.

\medskip
\begin{lstlisting}[caption=Externe bestanden uitvoeren.]
  <script type="application/javascript;version=1.7">
    Nacissus.interpreter.evaluateUrl('http://example.com/myJSfile.js');
  </script>
\end{lstlisting}

\medskip
\begin{lstlisting}[caption=Implementatie van Narcissus.evaluateUrl() (in lib/jsexec.js).]
  function evaluateUrl(u, p, f, l){
     eval_req.open('GET', u, false);
     eval_req.send(null);
     if (eval_req.status !== 200) {
        throw new Error("Error loading " + u);
     }
     return evaluate(eval_req.responseText,p,f,l);
  }
\end{lstlisting}

\section{Testprocess}
Omdat Narcissus slechts een research prototype is, was het nodig om de geschiktheid van Narcissus voor deze thesis grondig te onderzoeken. Hiervoor hebben we een testsuite ontwikkeld die Narcissus test op het correct uitvoeren van JavaScript.

\subsection{De Testsuite}
Een goede beschrijving van wat JavaScript moet doen, is terug te vinden in de ECMAScript specificaties \cite{ecma}.
Hiervoor zijn ook al reeds tests geschreven, die deze functionaliteiten testen \cite{ecmatest}. Deze testsuite bevat meer dan 10000 tests en kan gewoon in de browser uitgevoerd worden. Ook SpiderMonkey gebruikt deze tests. 
Aangezien de tests in Narcissus moeten uitgevoerd worden, moest er een alternatieve methode gezocht worden 
om deze tests toch te kunnen uitvoeren.

De tests die gebruikt worden zijn ook te downloaden via die site, in totaal dus iets meer dan 10000 
bestanden die allen een stukje JavaScript code bevatten dat een functionaliteit test. De bestanden 
zijn verspreid over verschillende mappen per hoofdstuk. De hoofstukken zijn dezelfde als in de ECMAScript specificaties \cite{ecma}.
De tests behandelen wel enkel hoofdstukken 7 tot en met 15. Dit is omdat de eerste 6 hoofdstukken van de specificaties geen echte functionaliteit beschrijven.
Dit kan later interessant zijn om te kunnen achterhalen welke delen er in Narcissus nog onvoldoende ondersteund worden.

Zoals reeds aangehaald zullen ook onder andere DOM, XHR en cookie nodig zijn. 
Sommige functionaliteiten zoals onder andere DOM, XHR, en cookie, vallen niet binnen de ECMA specificaties.
Voor deze functionaliteiten zullen er aanvullende tests geschreven moeten worden. 

\subsubsection{Aanpassingen aan de Testsuite}
\label{AanpassenTestSuite}

Het is onwenselijk dat 2 tests elkaar be\"invloeden, om dit te vermijden is het dus best om geen 2 
tests achter elkaar in hetzelfde venster uit te voeren. In de online testsuite wordt er telkens een 
nieuwe frame aangemaakt, daarin wordt de test met het script geladen en zo de resultaten opgevraagd. 
Dit bleek niet zo makkelijk te dupliceren te zijn, zeker om Narcissus telkens opnieuw mee in te 
laden en de test correct in Narcissus te laten uitvoeren. De methodes die nagaan of het correcte 
resultaat is verkregen zijn mits een lichte aanpassing wel gekopieerd (e.g. De methode die 
aangeeft dat een test een ander resultaat dan verwacht verkregen heeft). Deze functies moeten 
mee ingeladen worden in Narcissus voor de eigenlijke test ingeladen wordt, omdat de methodes in 
de tests ook in Narcissus uitgevoerd worden. Ook deze methodes zijn op voorhand getest, zodat er 
geen tests uit de testsuite zouden falen door het falen van deze hulpmethodes.

Zo kan er al getest worden voor elke test of deze slaagt. Uiteraard is het onbegonnen werk om ze 
allemaal een per een af te gaan en de resultaten te noteren. Daarvoor is er een script gemaakt dat 
zichzelf na het uitvoeren van een test kan doorsturen naar de volgende tot er geen test meer 
overblijft. Opnieuw niet zo magisch, het aanpassen van document.location laadt de ingegeven url 
in de frame waar het script uitgevoerd wordt. D.w.z. dat de gehele frame opnieuw wordt geladen, 
ook de bestanden van Narcissus.

Voor te bepalen welke test er geladen moet worden en welke test de volgende moet zijn is er 
nood aan een dynamische webtaal. Aangezien PHP eenvoudig te gebruiken is, wordt daarvoor 
geopteerd, in samenhang met een MySQL database. Een eerste script zorgt dat elke test in de 
database terecht komt en een uniek volgnummer krijgt, dit moet slechts eenmaal gebeuren. Vanaf 
dan kan er eenvoudig naar de volgende test doorverwezen worden. Door te beginnen met 
nummer 1 en elke keer te verhogen tot de nummer groter is dan het aantal tests in de database.

\medskip
\begin{lstlisting}
  $testfile = $test_model->getTest($_GET["scriptnr"]);
  loadTest("<?=$testfile?>");
  ...
  window.location = "chain.php?scriptnr="+(scriptNR+1):
\end{lstlisting}

Voor het bijhouden van de resultaten kan dan dezelfde database gebruiken. Na het uitvoeren er 
van, kan de eventuele fout weggeschreven worden voor die bijhorende test. Dit kan met XHR, 
waarvoor een apart PHP script zorgt voor de afhandeling van de database operaties. Er mag niet 
naar de volgende test gegaan worden alvorens er melding is gedaan van de eventuele fout. Als dit 
niet correct gedaan wordt en de XHR request is niet tijdig verzonden, zal de request ook niet 
verder afgehandeld worden, waardoor de mogelijkheid bestaat dat falende tests niet worden 
opgemerkt. Om hier zeker te kunnen van zijn kan er gebruik gemaakt worden van de callback 
parameter van XHR, die opgeroepen wordt na het verkrijgen van de response van de server. Door 
de methode die het doorverwijzen naar de volgende test afhandelt als callback te nemen, 
kan er geen foutmelding overgeslagen worden.

\subsection{Tests}

Aangezien de tests ook voor Spidermonkey gebruikt worden, is het interessant om de vergelijking 
te maken met deze JavaScript Engine die zich al bewezen heeft op het wereldwijde web. Mede ook 
omdat Narcissus uitgevoerd wordt in Spidermonkey, waardoor falende tests aan de basis kunnen 
liggen van falende tests in Narcissus.

Van de 10405 geteste files faalden er slechts 174 in SpiderMonkey. Narcissus doet het minder 
goed, er falen in totaal 2446 files (zie Figuur \ref{figTestRes1}). Gefaalde tests zijn in de eerste plaats de tests die niet slagen 
omdat de \$ERROR of \$FAIL methode wordt opgeroepen in de test. Deze 2 methodes zitten in de 
test om aan te geven of een test al dan niet faalt. Maar ook de tests waarbij een error gegooid 
wordt in SpiderMonkey, hierover later meer.

\begin{figure}
		\centering
 		\includegraphics[width=0.80\textwidth]{img/test_chart.png}
 		\caption{Testresultaten.}
		\label{figTestRes1}
\label{Testresultaten.}
\end{figure}

\subsection{Patches}

Nu de resultaten ter beschikking zijn, moet er gekeken worden wat de oorzaak is van deze falende 
tests. In de hoop dat enkele kleine aanpassingen, veel problemen oplossen. Deze analyse zal een 
eerste bijdrage zijn aan de volledige thesis. De patches die gedaan zullen worden kunnen gemeld 
worden aan Mozilla ter ondersteuning van de ontwikkeling van Narcissus. Het is niet de bedoeling 
om Narcissus foutloos te krijgen, een minimum aan functionaliteit ondersteunen volstaat voor het 
prototype.

\subsubsection{Patch 1: Undefined variables}

Een eerste probleem dat onderzocht is geweest, is het gebruik van ongedefinieerde variabelen en 
functies. Indien men een variabele "x" wilt gebruiken zonder dat deze eerst ergens is 
gedeclareerd, wordt er verwacht dat JavaScript een ReferenceError gooit. 

\medskip
\begin{lstlisting}[caption=Falende test.]
  try{
      eval("onbekende_var;");
      $ERROR("2.1.3 ACCESS UNDEFINED VARIABLES > ERROR EXPECTED");
   }catch(e){
      success("2.1.3 ACCESS UNDEFINED VARIABLES / ERROR EXCPETED: "+e.message);
   }
\end{lstlisting}

Na analyze van Narcissus blijkt dat Narcissus wel degelijk de verwachte fout gooit maar in de context van SpiderMonkey. Omdat de
tests draaien in de context van Narcissus kunnen zij deze fout niet vangen. Dit probleem kan opgelost worden door de fout door Narcissus te laten evalueren.

\medskip
\begin{lstlisting}[caption=Oplossing.]
  //oude Narcissus code
  function getValue(v) {
     ...
     throw new ReferenceError(v.propertyName + ' is not defined, ' + v.node.filename + ', ' + v.node.lineno);
     ...
  }
  
  //aangepaste code
  function getValue(v) {
     ...
     var e = 'throw new ReferenceError("'+ v.propertyName + ' is not defined, ' + v.node.filename + ', ' + v.node.lineno + '");';
     Narcissus.interpreter.evaluate(e);
     ...
  }
\end{lstlisting}

Het blijkt dat een groot deel van de tests faalt om gelijkaardige reden, fouten die vanwege de 
context niet kunnen opgevangen worden (Zie Figuur \ref{figTestResPie}). Voor een deel van de gevallen is dit opgelost, zonder 
hierbij nieuwe tests te doen falen. 

\subsubsection{Patch 2: intanceof}

Een andere reden waardoor verschillende tests faalde, was het gebruik van instanceof. Buiten het 
testen van de instanceof functionaliteit waren er nog een hoop tests die afhingen van het correct 
werken ervan. In het vorige voorbeeld wordt er bijvoorbeeld nagegaan dat de opgevangen fout 
een instantie is van ReferenceError. In Narcissus werd een eigen implementatie gebruikt van 
instanceof. Deze werkte niet correct en is vervangen door de instanceof van SpiderMonkey.

\subsubsection{Patch 3: XMLHttpRequest}

Er was ook een probleem met de constructor van het XMLHttpRequest (XHR) object, bij het oproepen van deze contructor zou er een 
TypeError gesmeten worden. Dit kwam omdat Narcissus een bepaalde functie, \_\_construct\_\_(),  van XHR niet kon vinden. Dit was een functie
die Narcissus zelf aan de prototype van het Function object zou moeten toegevoegd hebben die het gebruikt bij het evalueren van constructoren.

\medskip
\begin{lstlisting}[caption=Narcissus definieert de \_\_construct\_\_ functie op het prototype van het Function object.]
 definitions.defineProperty(Function.prototype, "__construct__",
        function (a, x) {
           a = Array.prototype.splice.call(a, 0, a.length);
           switch (a.length) {
              case 0:
                 return new this();
              case 1:
                 return new this(a[0]);
              case 2:
                 return new this(a[0], a[1]);
              case 3:
                 return new this(a[0], a[1], a[2]);
              default:
                 var argStr = "";
                 for (var i=0; i<a.length; i++) {
                    argStr += 'a[' + i + '],';
                 }
                 return eval('new this(' + argStr.slice(0,-1) + ');');
           }
        }, true, true, true);
\end{lstlisting}

De reden dat deze functie niet gedefinieerd is voor (XHR), is dat het een speciaal prototype heeft. Want je zou nochthans verwachten dat XHR, dat zelf ook een functie is, alle functionaliteiten van Function overerft.
XHR wordt namelijk beschikbaar gesteld aan JavaScript door Firefox via het XPCON systeem (een systeem dat c++ objecten beschikbaar kan stellen aan JavaScript code) en daardoor is het prototype
van XHR een zogenaamd "XPCON wrapped native object". Dit prototype is zo beveiligd dat zijn eigenschappen niet aangepast kunnen worden.
Het was daardoor nodig om de \_\_construct\_\_() functie rechtstreeks aan XHR toe te voegen.

\pagebreak

\medskip
\begin{lstlisting}[caption=De \_\_construct\_\_() functie wordt rechtreeks gedefinieerd op  XHR]
 definitions.defineProperty(XMLHttpRequest, "__construct__",
        function (a, x) {
           a = Array.prototype.splice.call(a, 0, a.length);
           switch (a.length) {
              case 0:
                 return new this();
              case 1:
                 return new this(a[0]);
              case 2:
                 return new this(a[0], a[1]);
              case 3:
                 return new this(a[0], a[1], a[2]);
              default:
                 var argStr = "";
                 for (var i=0; i<a.length; i++) {
                    argStr += 'a[' + i + '],';
                 }
                 return eval('new this(' + argStr.slice(0,-1) + ');');
           }
        }, true, true, true);
\end{lstlisting}


\subsubsection{Kleinere patches}

Daarbuiten zijn er ook kleinere patches gedaan. Het inlezen van getallen die beginnen met een 
punt of getallen die beginnen met een 0 gevolgd door een punt. Deze problemen situeerden zich in 
de lexer, bij het omzetten van de string werd teruggegeven het hoeveelste token het was in plaats 
van de waarde ervan. Op zich waren dit geen grote aanpassingen, maar het geeft wel een zicht op 
de werking van de lexer. Uiteraard lossen deze patches slechts enkele testgevallen op.

\subsection{Resultaten}

\begin{figure}
		\centering
 		\includegraphics[width=0.80\textwidth]{img/test_chart2.png}
 		\caption{Testresultaten na het patchen.}
		\label{figTestRes2}
\label{Testresultaten na het patchen.}
\end{figure}

Voor de nieuwe Narcissus slagen 292 test meer dan de versie waarmee er de eerste keer getest is geweest (zie Figuur \ref{figTestRes2}).
De falende tests zijn verspreid over de veschillende hoofdstukken (zie Figuur \ref{figTestResChap}). 

\pagebreak

De hoofdstukken beschrijven:
\begin{itemize}
  \setlength{\parskip}{0.0in}
  \setlength{\itemindent}{1.0em}
  \item Chapter 7: Lexical Conventions
  \item Chapter 8: Types
  \item Chapter 9: Type Conventions
  \item Chapter 10: Executable Code and Execution Contexts
  \item Chapter 11: Expressions
  \item Chapter 12: Statements
  \item Chapter 13: Function Definition
  \item Chapter 14: Program
  \item Chapter 15: Standard Built-in ECMAScript Objects
\end{itemize}

Er is dus geen een specifiek hoofdstuk dat slecht of niet ondersteund wordt, de grootste delen van elk hoofdstuk zijn ondersteund.
Van de overblijvende fouten falen er nog steeds 1041 omdat er een fout in SpiderMonkey context gesmeten wordt dat niet in
Narcissus context opgevangen kan worden. Verder zijn er 286 van de fouten de wijten aan het feit dat Narcissus ``use sctrict'' niet ondersteunt (Zie Figuur \ref{figTestResPie}).

\begin{figure}	
		\centering
 		\includegraphics[width=0.80\textwidth]{img/test_chapters_chart.png}
 		\caption{Testresultaten per hoofdstuk.}
		\label{figTestResChap}
\label{Testresultaten per hoofdstuk.}
\end{figure}

\begin{figure}
		\centering
 		\includegraphics[width=0.80\textwidth]{img/test_pie_chart.png}
 		\caption{Verhouding van tests die falen door uncaught Exceptions en use strict.}
		\label{figTestResPie}
\end{figure}

\pagebreak

\subsection{Conclusie}

Hierbij wordt het testprocess rond Narcissus afgerond. Van de overblijvende tests die falen door dat de fouten die gesmeten
worden in SpiderMonkey context, en dus niet opgevangen kunnen worden in Narcissus context, zijn er waarschijnlijk een deel die nog kunnen opgelost worden op dezelfde manier dan deze eerder beschreven. Het is wel zeker dat er nog fouten zijn die een fout smijten in SpiderMonkey context door andere redenen.

De tests die hier als 1 test beschouwd worden, zijn eigenlijk testbestanden die bestaan uit meerdere tests. Elke test controleert dan
een gelijkaardige functionaliteit. Het gebeurt dan wel dat juist een van de laatste tests uit een bestand faalt. Meestal is dit ook een iets $"$exotischer$"$ geval, waarbij meer uitzonderlijke functionaliteit getest wordt. Dit kan een vertekend beeld geven, omdat hetzelfde percentage van ondersteunde functionaliteit hoger ligt dan uit de tests blijkt.

Narcissus staat zeker niet op punt maar het wordt nog steeds verder ontwikkeld door Mozilla. Narcissus ondersteunt de basis functionaliteiten van JavaScript zo goed als volledig, het is vooral te wijten aan de meest exotischere features van JavaScript dat er zo veel tests falen.
Daardoor hebben we besloten dat Narcissus geschikt is om verder gebruikt te worden in het prototype.

